﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using XmlStudio.Interfaces;
using XmlStudio.Models;
using XmlStudio.DataLayer;

namespace XmlStudio.Tests.XsdTests {
    [TestClass]
    public class XsdStructureTest {
        private IXmlModel model;
        private const string XsPrefix = "xs";
        private const string XsNamespaceUri = "http://www.w3.org/2001/XMLSchema";

        public void TestInitialize() {
            this.model = ModelFactory.CreateXmlModel();
        }

        [TestMethod]
        public void XsdStructureAll() {
            var availableContent = XsdStructure.GetContent(XsdElement.All);
            Assert.IsTrue(new[] { 
                new XsdStructureItem { ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne}, 
                new XsdStructureItem{ ElementType = XsdElement.Element, Multiplicity = Multiplicity.ZeroOrMore}
            }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureAnnotation() {
            var availableContent = XsdStructure.GetContent(XsdElement.Annotation);

            var group = new XsdStructureGroup();
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.AppInfo, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Documentation, Multiplicity = Multiplicity.One });
            group.Operator = GroupOperator.Or;
            group.Multiplicity = Multiplicity.ZeroOrMore;

            Assert.IsTrue(new List<XsdStructureItem> { group }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureAny() {
            var availableContent = XsdStructure.GetContent(XsdElement.Any);
            Assert.IsTrue(new List<XsdStructureItem> { 
                        new XsdStructureItem { ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne } 
                    }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureAnyAttribute() {
            var availableContent = XsdStructure.GetContent(XsdElement.AnyAttribute);
            Assert.IsTrue(new List<XsdStructureItem>{
                        new XsdStructureItem{ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne}
                    }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureAppInfo() {
            var availableContent = XsdStructure.GetContent(XsdElement.AppInfo);
            Assert.IsTrue(new List<XsdStructureItem>{
                        new XsdStructureItem{ElementType = XsdElement.AnyWellFormedXml, Multiplicity = Multiplicity.ZeroOrMore}
                    }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureAttribute() {
            var availableContent = XsdStructure.GetContent(XsdElement.Attribute);
            Assert.IsTrue(new List<XsdStructureItem> {
                        new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                        new XsdStructureItem{ ElementType = XsdElement.SimpleType, Multiplicity = Multiplicity.ZeroOrOne}
                    }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureAttributeGroup() {
            var availableContent = XsdStructure.GetContent(XsdElement.AttributeGroup);
            var group = new XsdStructureGroup();
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Attribute, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.AttributeGroup, Multiplicity = Multiplicity.One });
            group.Operator = GroupOperator.Or;
            group.Multiplicity = Multiplicity.ZeroOrMore;
            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                            group,
                            new XsdStructureItem{ElementType = XsdElement.AnyAttribute, Multiplicity = Multiplicity.ZeroOrOne}
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureChoice() {
            var availableContent = XsdStructure.GetContent(XsdElement.Choice);
            var group = new XsdStructureGroup();
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Element, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Group, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Choice, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Sequence, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Any, Multiplicity = Multiplicity.One });
            group.Multiplicity = Multiplicity.ZeroOrMore;
            group.Operator = GroupOperator.Or;
            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                            group
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureComplexContent() {
            var availableContent = XsdStructure.GetContent(XsdElement.ComplexContent);
            var group = new XsdStructureGroup();
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Restriction, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Extension, Multiplicity = Multiplicity.One });
            group.Operator = GroupOperator.Or;
            group.Multiplicity = Multiplicity.One;
            Assert.IsTrue(new List<XsdStructureItem>{
                        new XsdStructureItem { ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                        group
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureComplexType() {
            var availableContent = XsdStructure.GetContent(XsdElement.ComplexType);

            var group01 = new XsdStructureGroup();
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.Group, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.All, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.Choice, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.Sequence, Multiplicity = Multiplicity.One });
            group01.Operator = GroupOperator.Or;
            group01.Multiplicity = Multiplicity.ZeroOrOne;

            var group02 = new XsdStructureGroup();
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.Attribute, Multiplicity = Multiplicity.One });
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.AttributeGroup, Multiplicity = Multiplicity.One });
            group02.Multiplicity = Multiplicity.ZeroOrMore;
            group02.Operator = GroupOperator.Or;

            var group03 = new XsdStructureGroup();
            group03.Items.Add(group02);
            group03.Items.Add(new XsdStructureItem { ElementType = XsdElement.AnyAttribute, Multiplicity = Multiplicity.ZeroOrOne });
            group03.Multiplicity = Multiplicity.One;
            group03.Operator = GroupOperator.And;

            var group04 = new XsdStructureGroup();
            group04.Items.Add(group01);
            group04.Items.Add(group03);
            group04.Multiplicity = Multiplicity.One;
            group04.Operator = GroupOperator.And;

            var group05 = new XsdStructureGroup();
            group05.Items.Add(new XsdStructureItem { ElementType = XsdElement.SimpleContent, Multiplicity = Multiplicity.One });
            group05.Items.Add(new XsdStructureItem { ElementType = XsdElement.ComplexContent, Multiplicity = Multiplicity.One });
            group05.Items.Add(group04);

            Assert.IsTrue(new List<XsdStructureItem>{
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                            group05
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureDocumentation() {
            var availableContent = XsdStructure.GetContent(XsdElement.Documentation);
            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.AnyWellFormedXml, Multiplicity = Multiplicity.ZeroOrMore}
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureElement() {
            var availableContent = XsdStructure.GetContent(XsdElement.Element);
            var group01 = new XsdStructureGroup();
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.SimpleType, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.ComplexType, Multiplicity = Multiplicity.One });
            group01.Multiplicity = Multiplicity.ZeroOrOne;
            group01.Operator = GroupOperator.Or;

            var group02 = new XsdStructureGroup();
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.Unique, Multiplicity = Multiplicity.One });
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.Key, Multiplicity = Multiplicity.One });
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.KeyRef, Multiplicity = Multiplicity.One });
            group02.Multiplicity = Multiplicity.ZeroOrMore;
            group02.Operator = GroupOperator.Or;

            var group03 = new XsdStructureGroup();
            group03.Items.Add(group01);
            group03.Items.Add(group02);
            group03.Multiplicity = Multiplicity.One;
            group03.Operator = GroupOperator.And;

            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                            group03
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureExtension() {
            var availableContent = XsdStructure.GetContent(XsdElement.Extension);
            var group01 = new XsdStructureGroup();
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.Group, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.All, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.Choice, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.Sequence, Multiplicity = Multiplicity.One });
            group01.Multiplicity = Multiplicity.ZeroOrOne;
            group01.Operator = GroupOperator.Or;

            var group02 = new XsdStructureGroup();
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.Attribute, Multiplicity = Multiplicity.One });
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.AttributeGroup, Multiplicity = Multiplicity.One });
            group02.Multiplicity = Multiplicity.ZeroOrMore;
            group02.Operator = GroupOperator.Or;

            var group03 = new XsdStructureGroup();
            group03.Items.Add(group01);
            group03.Items.Add(group02);
            group03.Items.Add(new XsdStructureItem { ElementType = XsdElement.AnyAttribute, Multiplicity = Multiplicity.ZeroOrOne });

            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                            group03
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureField() {
            var availableContent = XsdStructure.GetContent(XsdElement.Field);
            Assert.IsTrue(new List<XsdStructureItem> {
                        new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne}
                    }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureGroup() {
            var availableContent = XsdStructure.GetContent(XsdElement.Group);
            var group = new XsdStructureGroup();
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.All, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Choice, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Sequence, Multiplicity = Multiplicity.One });
            group.Multiplicity = Multiplicity.ZeroOrOne;
            group.Operator = GroupOperator.Or;

            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                            group
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureImport() {
            var availableContent = XsdStructure.GetContent(XsdElement.Import);
            Assert.IsTrue(new List<XsdStructureItem>{
                        new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne}
                    }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureInclude() {
            var availableContent = XsdStructure.GetContent(XsdElement.Include);
            Assert.IsTrue(new List<XsdStructureItem>{
                        new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne}
                    }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureKey() {
            var availableContent = XsdStructure.GetContent(XsdElement.Key);
            var group = new XsdStructureGroup();
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Selector, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Field, Multiplicity = Multiplicity.OneOrMore });
            group.Multiplicity = Multiplicity.One;
            group.Operator = GroupOperator.And;

            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne },
                            group
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureKeyRef() {
            var availableContent = XsdStructure.GetContent(XsdElement.KeyRef);
            var group = new XsdStructureGroup();
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Selector, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Field, Multiplicity = Multiplicity.OneOrMore });
            group.Multiplicity = Multiplicity.One;
            group.Operator = GroupOperator.And;

            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne },
                            group
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureList() {
            var availableContent = XsdStructure.GetContent(XsdElement.List);
            Assert.IsTrue(new List<XsdStructureItem> {
                        new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                        new XsdStructureItem{ ElementType = XsdElement.SimpleType, Multiplicity = Multiplicity.ZeroOrOne}
                    }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureNotation() {
            var availableContent = XsdStructure.GetContent(XsdElement.Notation);
            Assert.IsTrue(new List<XsdStructureItem>{
                        new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne}
                    }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureRedefine() {
            var availableContent = XsdStructure.GetContent(XsdElement.Redefine);
            var group01 = new XsdStructureGroup();
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.SimpleType, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.ComplexType, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.Group, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.AttributeGroup, Multiplicity = Multiplicity.One });
            group01.Multiplicity = Multiplicity.One;
            group01.Operator = GroupOperator.Or;

            var group02 = new XsdStructureGroup();
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.One });
            group02.Items.Add(group01);
            group02.Multiplicity = Multiplicity.ZeroOrMore;
            group02.Operator = GroupOperator.Or;

            Assert.IsTrue(new List<XsdStructureItem>{
                            group02
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureSelector() {
            var availableContent = XsdStructure.GetContent(XsdElement.Selector);
            Assert.IsTrue(new List<XsdStructureItem>{
                        new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne}
                    }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureSequence() {
            var availableContent = XsdStructure.GetContent(XsdElement.Sequence);
            var group = new XsdStructureGroup();
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Element, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Group, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Choice, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Sequence, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Any, Multiplicity = Multiplicity.One });
            group.Multiplicity = Multiplicity.ZeroOrMore;
            group.Operator = GroupOperator.Or;

            Assert.IsTrue(new List<XsdStructureItem>{
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                            group
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureSchema() {
            var availableContent = XsdStructure.GetContent(XsdElement.Schema);
            var group01 = new XsdStructureGroup();
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.Include, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.Import, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.Redefine, Multiplicity = Multiplicity.One });
            group01.Items.Add(new XsdStructureItem { ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.One });
            group01.Multiplicity = Multiplicity.ZeroOrMore;
            group01.Operator = GroupOperator.Or;

            var group02 = new XsdStructureGroup();
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.SimpleType, Multiplicity = Multiplicity.One });
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.ComplexType, Multiplicity = Multiplicity.One });
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.Group, Multiplicity = Multiplicity.One });
            group02.Items.Add(new XsdStructureItem { ElementType = XsdElement.AttributeGroup, Multiplicity = Multiplicity.One });
            group02.Multiplicity = Multiplicity.One;
            group02.Operator = GroupOperator.Or;

            var group03 = new XsdStructureGroup();
            group03.Items.Add(group02);
            group03.Items.Add(new XsdStructureItem { ElementType = XsdElement.Element, Multiplicity = Multiplicity.One });
            group03.Items.Add(new XsdStructureItem { ElementType = XsdElement.Attribute, Multiplicity = Multiplicity.One });
            group03.Items.Add(new XsdStructureItem { ElementType = XsdElement.Notation, Multiplicity = Multiplicity.One });
            group03.Multiplicity = Multiplicity.One;
            group03.Operator = GroupOperator.Or;

            var group04 = new XsdStructureGroup();
            group04.Items.Add(group03);
            group04.Items.Add(new XsdStructureItem { ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrMore });
            group04.Multiplicity = Multiplicity.ZeroOrMore;
            group04.Operator = GroupOperator.And;

            Assert.IsTrue(new List<XsdStructureItem> {
                            group01,
                            group04
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureSimpleContent() {
            var availableContent = XsdStructure.GetContent(XsdElement.SimpleContent);
            var group = new XsdStructureGroup();
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Restriction, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Extension, Multiplicity = Multiplicity.One });

            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                            group
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureSimpleType() {
            var availableContent = XsdStructure.GetContent(XsdElement.SimpleType);

            var group = new XsdStructureGroup();
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Restriction, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.List, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Union, Multiplicity = Multiplicity.One });
            group.Multiplicity = Multiplicity.One;
            group.Operator = GroupOperator.Or;

            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                            group
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureUnion() {
            var availableContent = XsdStructure.GetContent(XsdElement.Union);
            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                            new XsdStructureItem{ ElementType = XsdElement.SimpleType, Multiplicity = Multiplicity.ZeroOrMore}
                        }.SequenceEqual(availableContent));
        }

        [TestMethod]
        public void XsdStructureUnique() {
            var availableContent = XsdStructure.GetContent(XsdElement.Unique);

            var group = new XsdStructureGroup();
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Selector, Multiplicity = Multiplicity.One });
            group.Items.Add(new XsdStructureItem { ElementType = XsdElement.Field, Multiplicity = Multiplicity.OneOrMore });

            Assert.IsTrue(new List<XsdStructureItem> {
                            new XsdStructureItem{ ElementType = XsdElement.Annotation, Multiplicity = Multiplicity.ZeroOrOne},
                            group
                        }.SequenceEqual(availableContent));
        }
    }
}
